Skip to content

feat(web): React UI v2.0 — Phases 0-6 (backend + scaffold + shell + canvas + monitors + modals)#34

Merged
aksOps merged 4 commits into
mainfrom
feat/web-v2-phase-0-to-6
May 16, 2026
Merged

feat(web): React UI v2.0 — Phases 0-6 (backend + scaffold + shell + canvas + monitors + modals)#34
aksOps merged 4 commits into
mainfrom
feat/web-v2-phase-0-to-6

Conversation

@aksOps

@aksOps aksOps commented May 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Consolidation PR. Ships the React UI v2.0 stack from web/ end-to-end:

  • Phase 0: backend foundation — /api/v1/* router move, 5 sidecar endpoints, env-driven CORS, StaticFiles + SPA fallback.
  • Phase 1: Vite 7 + React 19 + TS scaffold, Tailwind v4 + CSS tokens, Geist fonts, TS design tokens, Vitest, 7 component primitives.
  • Phase 2: TS API types + apiFetch + SSE/WS hooks + sessionReducer + 6 data hooks + selectedRef Context.
  • Phase 3: 4 shell components + App wiring — first runnable end-to-end render.
  • Phase 4: canvas components (CanvasHead, Sidenote, ToolCallCard, HITLBand, Turn, Transcript, SessionCanvas) — first real session render.
  • Phase 5: Monitor wrapper + 6 panels + MonitorRail assembly — full 3-pane shell rendering end-to-end.
  • Phase 6: NewSessionModal + ApproveRationaleModal + ConfirmModal; SessionCanvas wires HITLBand + CanvasHead actions; 3 Playwright E2E specs (new-session live + hitl-approve soft-skip + retry-after-error live).

Bundled with chore(sonar): Tier 1 cleanup (was unmerged on a stale branch).

Verification (locally)

  • npm run lint — 0 errors, 2 acceptable react-refresh warnings
  • npm run typecheck — clean
  • npm run test:unit — 41 files / 168 tests pass
  • npm run build — 308 kB raw / 94 kB gzip
  • Playwright (against uvicorn + built SPA at :8000):
    • new-session.live.spec.tsPASS
    • retry-after-error.live.spec.tsPASS
    • hitl-approve.live.spec.tsSKIP (no HITL pause in smoke config; spec is wired but config-dependent)

Stacked PRs

This is the base of a 4-PR stack:

  1. THIS PR — Phases 0-6 consolidation
  2. feat/web-v2-phase-7 → responsive (Tasks 57-61)
  3. feat/web-v2-phase-8 → build/deploy/CI (Tasks 62-69)
  4. feat/web-v2-phase-9 → Streamlit retirement + parity (Tasks 70-71)

After this PR squash-merges, PRs 2-4 will be re-targeted to main and rebased.

Test plan

  • CI Web CI workflow (added in PR 3) — once Phase 8 lands, this PR retroactively passes via squash-then-test
  • Manual: cd web && npm run build && cd .. && uv run uvicorn runtime.api:get_app --factory --port 8000 → open http://localhost:8000/

🤖 Generated with Claude Code

aksOps added 4 commits May 16, 2026 09:36
- web/vitest.config.ts: add tests/e2e/** to exclude list so vitest no
  longer tries to evaluate the Playwright spec (was failing with
  "two different versions of @playwright/test" error).
- web/tests/e2e/new-session.live.spec.ts: default E2E_BASE_URL to
  http://localhost:5173 (was a remote deploy URL) so the loop and
  CI can run against locally-served stack.

Verified: npm run test:unit → 39 files, 156 passed.
- web/src/modals/ApproveRationaleModal.tsx: Modal with rationale
  textarea + optional templates row + error envelope; POSTs to
  /api/v1/sessions/{sid}/approvals/{tool_call_id} with
  { decision: 'approve', approver, rationale }.
- web/src/canvas/SessionCanvas.tsx: derives hitlContext from
  state.toolCalls (finds first pending_approval); wires plain
  onApprove (direct POST, rationale=null), onApproveWithRationale
  (opens modal). Reject + Stop still no-ops, picked up by Task 53.
- web/tests/component/ApproveRationaleModal.test.tsx: 6 tests
  covering disabled state, submit, template chips, error envelope.

Verified: typecheck clean; vitest 40 files / 162 tests pass; build 308 kB / 94 kB gzip.
- web/src/modals/ConfirmModal.tsx: generic confirm dialog with
  { title, body, confirmLabel, destructive, onConfirm }. Destructive
  variant flips primary button to --danger and stamps a
  data-destructive='true' attribute for test selection.
- web/src/components/Modal.tsx: PrimaryAction.destructive flag.
- web/src/canvas/SessionCanvas.tsx: wire HITLBand onReject -> reject
  ConfirmModal (POST decision=reject); CanvasHead onStop -> stop
  ConfirmModal (DELETE /sessions/{sid}).
- web/tests/component/ConfirmModal.test.tsx: 6 tests covering open,
  destructive eyebrow + data-destructive attr, confirm, async error,
  custom eyebrow.

Verified: typecheck clean; vitest 41 files / 168 tests pass.
- web/tests/e2e/hitl-approve.live.spec.ts: creates a session via API,
  polls for status=awaiting_input (60s timeout), opens the SPA on the
  paused session, clicks Approve in HITLBand, asserts the band hides
  and the backend status moves past awaiting_input. Soft-skips when
  the backend never reaches awaiting_input (config-dependent gating).
- web/tests/e2e/retry-after-error.live.spec.ts: end-to-end Stop +
  retry flow — creates a session via the New Session modal (so the
  canvas auto-selects it), clicks Stop, confirms the destructive
  ConfirmModal, asserts the session reaches a terminal state, then
  re-creates with the same query and verifies a fresh sid.

Local verification against uvicorn:8000:
  new-session.live: PASS
  hitl-approve.live: SKIPPED (no HITL pause in smoke config)
  retry-after-error.live: PASS
@sonarqubecloud

Copy link
Copy Markdown

@aksOps aksOps merged commit 9b411b6 into main May 16, 2026
9 checks passed
@aksOps aksOps deleted the feat/web-v2-phase-0-to-6 branch May 16, 2026 09:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant